import React, { Component } from 'react';
import {Flex, Icon, ImagePicker, NavBar, Progress} from "antd-mobile";
import ReactCropper from 'react-cropper';
import 'cropperjs/dist/cropper.css'; // 引入Cropper对应的css
import "./css/style.less";
import {axiosFetch, handleResp} from "../../util/common/http";
import constant from "../../util/common/constant";
import DataLoading from "../loading-data";
import PicCarousel from "../pic-carousel";

export interface IMyCopperProps {
  // 上传什么类型(1:菜品图片, 2:用户头像)
  type: "1"|"2";
  // 已存在的图片
  files?: Array<any>;
  // 最少上传几个
  min: number;
  // 最多上传几个
  max: number;
  // 确定选择
  onSubmit: (fileUrl: string) => void;
  // 删除图片
  onRemove: (index?: number) => void;
}

/**
 * 使用antd mobile的ImagePicker结合react-cropper实现图片裁剪上传
 */
export default class MyCopper extends Component<IMyCopperProps, any> {
  cropper: any;

  constructor(props: IMyCopperProps) {
    super(props);
    const files = this._getFilesStateFromProps();
    this.state = {
      // 是否展示弹层走马灯图片
      showCarousel: false,
      // 已选择的多个文件
      files: files,
      // 裁剪遮罩层是否显示
      copperVisible: false,
      // 是否正在加载待裁剪的图片
      loadingCopperFile: false,
      // 当前正在裁剪的图片名称
      copperFileName: null,
      // 当前正在裁剪的图片资源
      copperFileSrc: null,
      // 是否正在上传图片
      submitting: false,
      // 上传进度%
      completeProgress: 0,
    }
  }

  componentDidUpdate(prevProps: Readonly<IMyCopperProps>, prevState: Readonly<any>) {
    if (prevProps.files !== this.props.files) {
      const files = this._getFilesStateFromProps();
      this.setState({files: files});
    }
  }

  _getFilesStateFromProps = () => {
    let filesTmp:Array<any> = [];
    if (this.props.files) {
      this.props.files.forEach((file) => file.url = constant.IMG_HOST + file.url);
      filesTmp = this.props.files;
    }
    return filesTmp;
  };

  render() {
    const { files, copperVisible, loadingCopperFile } = this.state;
    return (
      <div className="bb-image-picker-box">
        {/* 图片选择器 */}
        <ImagePicker
          files={files}
          onChange={this._onChange}
          onImageClick={() => this.setState({showCarousel: true})}
          selectable={files.length < this.props.max}
        />

        {/* 走马灯图片 */}
        {
          this.state.showCarousel &&
          <PicCarousel picArr={files.map((file:any) => file.url)}
                       onClose={() => this.setState({showCarousel: false})} />
        }

        {/* 裁剪图片遮罩层 */}
        <div className={`bb-copper-box${copperVisible ? "" : " copper-hidden"}`}>

          {/* 导航栏 */}
          <NavBar
            mode="dark"
            icon={<Icon type="left" />}
            onLeftClick={this._onClose}
            rightContent={<Flex onClick={this._onSubmit}><Icon type="check"/><span>确定</span></Flex>}
          >
            裁剪图片
          </NavBar>

          {/* 加载图片的loading */}
          {loadingCopperFile && <DataLoading />}

          {/* 上传进度条 */}
          {!loadingCopperFile && <Progress percent={this.state.completeProgress} position="normal"/>}

          {/* 裁剪图片区域 */}
          {
            !loadingCopperFile &&
            <ReactCropper
              className="cropper"
              ref={cropper => (this.cropper = cropper)}

              src={this.state.copperFileSrc} // 图片路径或base64值
              viewMode={1} // 定义cropper的视图模式
              zoomable={false} // 是否允许放大图像
              aspectRatio={1 / 1} // image的纵横比
              guides={true} // 显示在裁剪框上方的虚线
              background={true} // 是否显示背景的马赛克
            />
          }
        </div>
      </div>
    )
  }

  /**
   * 图片选择器变动回调事件
   * @param files 多个文件
   * @param operationType 操作类型
   * @param index 操作类型时删除时的索引
   * @private
   */
  _onChange = (files: Array<any>, operationType: string, index?: number) => {
    if (operationType === "add") {
      const fileToCopperTmp = files[files.length - 1].file;
      this.setState({
        copperVisible: true,
        loadingCopperFile: true,
        copperFileName: null,
        copperFileSrc: null,
      });

      // 加载大图片时,时间可能会比较长(实测5MB的图片,差不多要加载4-5秒),故采取异步加载的方式
      const fileReader = new FileReader();
      fileReader.onload = (e: any) => {
        const dataURL = e.target.result;
        this.setState({
          loadingCopperFile: false,
          copperFileName: fileToCopperTmp.name,
          copperFileSrc: dataURL
        });
      };
      fileReader.readAsDataURL(fileToCopperTmp);

    } else {
      this.setState({
        files,
      });
      this.props.onRemove(index);
    }
  };

  /**
   * 上传资源
   * @private
   */
  _onSubmit = () => {
    if (!this.state.submitting) {
      this.cropper.getCroppedCanvas().toBlob(async (blob: Blob) => {
        this.setState({submitting: true});

        const url = "/resource/upload";
        const formData = new FormData();
        formData.append('file', blob, this.state.copperFileName);
        formData.append("type", this.props.type);
        // 上传图片
        const resp = await axiosFetch(url, {
          headers: { "Content-Type": "multipart/form-data" },
          //添加上传进度监听事件
          onUploadProgress: e => {
            const completeProgress = (e.loaded / e.total * 100) || 0;
            this.setState({completeProgress});
          },
          method: 'POST',
          data: formData
        });
        if (handleResp(resp)) {
          this.setState({
            files: this.state.files.concat({url: constant.IMG_HOST + resp.context}),
            submitting: false,
            completeProgress: 0,
            copperVisible: false,
            loadingCopperFile: false,
            copperFileName: null,
            copperFileSrc: null,
          });
          // 将文件相对路径透传给父组件
          this.props.onSubmit(resp.context);
        } else {
          this.setState({
            submitting: false,
            completeProgress: 0,
            copperVisible: false,
            loadingCopperFile: false,
            copperFileName: null,
            copperFileSrc: null,
          });
        }
        // 格式image/jpeg 质量0.3(由于手机图片太大了,这边缩减图片质量)
      }, "image/jpeg", 0.3);
    }
  };

  /**
   * 关闭遮罩层
   * @private
   */
  _onClose = () => {
    this.setState({
      copperVisible: false,
      loadingCopperFile: false,
      copperFileName: null,
      copperFileSrc: null,
    });
  };
}
